package com.lyf.lottery.exception;

import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.lyf.common.api.CommonResult;
import com.lyf.common.exception.ApiException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import java.text.ParseException;
import java.util.List;
import java.util.Map;

import static com.lyf.common.api.ResultCode.*;


/**
 * @author yangdong
 * @since 2020/10/13 19:57
 */
@ControllerAdvice
@Slf4j
public class GlobalException {

    /**
     * 系统内部错误（未知异常）
     *
     * @param ex 异常
     * @return
     */
    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public CommonResult sysException(Exception ex) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 打印请求 url
        log.warn("Request Info: [ HTTP Method:{}，URL: {}]", request.getMethod(), request.getRequestURL().toString());
        log.error("Exception:", ex);
        if (ex instanceof HttpRequestMethodNotSupportedException) {
            return CommonResult.failed(METHOD_NOT_SUPPORTED);
        } else if (ex instanceof BindException) {
            BindException e = (BindException) ex;
            CommonResult<Map<String, String>> failed = CommonResult.failed(PARAM_VIOLATION_ERROR);
            BindingResult bindingResult = e.getBindingResult();
            List<FieldError> fieldErrors = bindingResult.getFieldErrors();
            StringBuilder sBuilder = new StringBuilder();
            if (fieldErrors.size() != 0) {
                fieldErrors.forEach(error -> {
                    sBuilder.append(error.getDefaultMessage()).append(",");
                });
                failed.setMsg(sBuilder.toString());
            }
            return failed;
        } else if (ex instanceof MethodArgumentNotValidException) {
            MethodArgumentNotValidException e = (MethodArgumentNotValidException) ex;
            BindingResult bindingResult = e.getBindingResult();
            CommonResult<Map<String, String>> failed = CommonResult.failed(PARAM_VIOLATION_ERROR);
            List<FieldError> fieldErrors = bindingResult.getFieldErrors();
            StringBuilder sBuilder = new StringBuilder();
            if (fieldErrors.size() != 0) {
                fieldErrors.forEach(error -> {
                    sBuilder.append(error.getDefaultMessage()).append(",");
                });
                failed.setMsg(sBuilder.toString());
            }
            return failed;
        } else if (ex instanceof ConstraintViolationException) {
            return CommonResult.failed(PARAM_VIOLATION_ERROR);
        } else if (ex instanceof MissingServletRequestParameterException) {
            return CommonResult.failed(PARAM_MISS_ERROR);
        } else if (ex instanceof InvalidFormatException) {
            return CommonResult.failed(PARAM_TYPE_ERROR, ex.getMessage());
        }  else if (ex instanceof MethodArgumentTypeMismatchException) {
            return CommonResult.failed(PARAM_TYPE_ERROR);
        }  else if (ex instanceof ParseException) {
            return CommonResult.failed(DATE_PARSE_ERROR);
        } else if (ex instanceof HttpMessageNotReadableException) {
            return CommonResult.failed(HTTP_MESSAGE_NOT_READABLE);
        } else if (ex instanceof ApiException) {
            ApiException e = (ApiException) ex;
            return CommonResult.failed(e.getErrorCode(),e.getMessage());
        } else {
            return CommonResult.failed(FAILED);
        }
    }
}
